{/* Copyright 2025 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:react-aria-components';
import {PropTable, HeaderInfo, TypeLink, PageDescription, StateTable, ContextTable, ClassAPI} from '@react-spectrum/docs';
import styles from '@react-spectrum/docs/src/docs.css';
import packageData from 'react-aria-components/package.json';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import {StarterKits} from '@react-spectrum/docs/src/StarterKits';
import Anatomy from '@react-aria/toast/docs/toast-anatomy.svg';
import {Keyboard} from '@react-spectrum/text';
import {InlineAlert, Content, Heading} from '@adobe/react-spectrum';

---
category: Status
keywords: [toast, notifications, alert, aria]
type: component
preRelease: alpha
---

# Toast

<PageDescription>{docs.exports.UNSTABLE_Toast.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ToastRegion', 'Toast']}
  sourceData={[
    {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/'}
  ]} />

<InlineAlert variant="notice" marginTop={60}>
  <Heading>Under construction</Heading>
  <Content>This component is in <strong>alpha</strong>. More documentation is coming soon!</Content>
</InlineAlert>

## Example

First, render a `ToastRegion` in the root of your app.

```tsx example hidden export=true
import {UNSTABLE_ToastRegion as ToastRegion, UNSTABLE_Toast as Toast, UNSTABLE_ToastQueue as ToastQueue, UNSTABLE_ToastContent as ToastContent, Button, Text} from 'react-aria-components';
import {X} from 'lucide-react';

// Define the type for your toast content.
interface MyToastContent {
  title: string,
  description?: string
}

// Create a global ToastQueue.
export const queue = new ToastQueue<MyToastContent>();

// Render a <ToastRegion> in the root of your app.
export function App() {
  return (
    <>
      <ToastRegion queue={queue}>
        {({toast}) => (
          <Toast toast={toast}>
            <ToastContent>
              <Text slot="title">{toast.content.title}</Text>
              <Text slot="description">{toast.content.description}</Text>
            </ToastContent>
            <Button slot="close"><X size={16} /></Button>
          </Toast>
        )}
      </ToastRegion>
      {/* Your app here */}
    </>
  );
}
```

Then, you can trigger a toast from anywhere using the exported `queue`.

```tsx example
<Button
  onPress={() => queue.add({
    title: 'Toast complete!',
    description: 'Great success.'
  })}>
  Toast
</Button>
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>

```css hidden
@import './Button.mdx' layer(button);
```

```css
@import "@react-aria/example-theme";

.react-aria-ToastRegion {
  position: fixed;
  bottom: 16px;
  right: 16px;
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  border-radius: 8px;
  outline: none;

  &[data-focus-visible] {
    outline: 2px solid slateblue;
    outline-offset: 2px;
  }
}

.react-aria-Toast {
  display: flex;
  align-items: center;
  gap: 16px;
  background: slateblue;
  color: white;
  padding: 12px 16px;
  border-radius: 8px;
  outline: none;

  &[data-focus-visible] {
    outline: 2px solid slateblue;
    outline-offset: 2px;
  }

  .react-aria-ToastContent {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0px;

    [slot=title] {
      font-weight: bold;
    }
  }

  .react-aria-Button[slot=close] {
    flex: 0 0 auto;
    background: none;
    border: none;
    appearance: none;
    border-radius: 50%;
    height: 32px;
    width: 32px;
    font-size: 16px;
    border: 1px solid white;
    color: white;
    padding: 0;
    outline: none;

    &[data-focus-visible] {
      box-shadow: 0 0 0 2px slateblue, 0 0 0 4px white;
    }

    &[data-pressed] {
      background: rgba(255, 255, 255, 0.2);
    }
  }
}
```

</details>

## Features

There is no built in way to display toast notifications in HTML. `<ToastRegion>` and `<Toast>` help achieve accessible toasts that can be styled as needed.

* **Accessible** – Toasts follow the [ARIA alertdialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/). They are rendered in a [landmark region](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/), which keyboard and screen reader users can easily jump to when an alert is announced.
* **Focus management** – When a toast unmounts, focus is moved to the next toast if any. Otherwise, focus is restored to where it was before navigating to the toast region.

## Anatomy

<Anatomy role="img" aria-label="Toast anatomy diagram, showing the toast's title and close button within the toast region." />

A `<ToastRegion>` is an [ARIA landmark region](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/) labeled "Notifications" by default. A `<ToastRegion>` accepts a function to render one or more visible toasts, in chronological order. When the limit is reached, additional toasts are queued until the user dismisses one. Each `<Toast>` is a non-modal ARIA [alertdialog](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/), containing the content of the notification and a close button. The toast's content gets announced by screen readers when the toast appears, so it is recommended to render the close button as a sibling of `<ToastContent>` instead of inside it, but this is not a requirement.

Landmark regions including the toast container can be navigated using the keyboard by pressing the <Keyboard>F6</Keyboard> key to move forward, and the <Keyboard>Shift</Keyboard> + <Keyboard>F6</Keyboard> key to move backward. This provides an easy way for keyboard users to jump to the toasts from anywhere in the app. When the last toast is closed, keyboard focus is restored.

```tsx
import {ToastRegion, Toast, ToastContent, Text, Button} from 'react-aria-components';

<ToastRegion>
  {({toast}) => (
    <Toast toast={toast}>
      <ToastContent>
        <Text slot="title" />
        <Text slot="description" />
      </ToastContent>
      <Button slot="close" />
    </Toast>
  )}
</ToastRegion>
```

## Auto-dismiss

Toasts support a `timeout` option to automatically hide them after a certain amount of time. For accessibility, toasts should have a minimum timeout of 5 seconds to give users enough time to read them. If a toast includes action buttons or other interactive elements it should not auto dismiss. In addition, timers will automatically pause when the user focuses or hovers over a toast.

Be sure only to automatically dismiss toasts when the information is not important, or may be found elsewhere. Some users may require additional time to read a toast message, and screen zoom users may miss toasts entirely.

```tsx example
<Button
  /*- begin highlight -*/
  onPress={() => queue.add({title: 'Toast is done!'}, {timeout: 5000})}
  /*- end highlight -*/
>
  Show toast
</Button>
```

## Programmatic dismissal

Toasts may be programmatically dismissed if they become irrelevant before the user manually closes them. `queue.add` returns a key for the toast which may be passed to `queue.close` to dismiss the toast.

```tsx example
function Example() {
  let [toastKey, setToastKey] = React.useState(null);

  return (
    <Button
      onPress={() => {
        if (!toastKey) {
          ///- begin highlight -///
          setToastKey(queue.add({title: 'Unable to save'}, {onClose: () => setToastKey(null)}));
          ///- end highlight -///
        } else {
          ///- begin highlight -///
          queue.close(toastKey);
          ///- end highlight -///
        }
      }}>
      {toastKey ? 'Hide' : 'Show'} Toast
    </Button>
  );
}
```

## Animations

Toast entry and exit animations can be done using third party animation libraries like [Motion](https://motion.dev/), or using native [CSS view transitions](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API).

This example shows how to use the `wrapUpdate` option of `ToastQueue` to wrap state updates in a CSS view transition. The `toast.key` can be used to assign a `viewTransitionName` to each `Toast`.

```tsx example
import {flushSync} from 'react-dom';

const queue = new ToastQueue<MyToastContent>({
  /*- begin highlight -*/
  // Wrap state updates in a CSS view transition.
  wrapUpdate(fn) {
    if ('startViewTransition' in document) {
      document.startViewTransition(() => {
        flushSync(fn);
      });
    } else {
      fn();
    }
  }
  /*- end highlight -*/
});

<ToastRegion queue={queue}>
  {({toast}) => (
    <Toast
      /*- begin highlight -*/
      style={{viewTransitionName: toast.key}}
      /*- end highlight -*/
      toast={toast}>
      <ToastContent>
        <Text slot="title">{toast.content.title}</Text>
        <Text slot="description">{toast.content.description}</Text>
      </ToastContent>
      <Button slot="close"><X size={16} /></Button>
    </Toast>
  )}
</ToastRegion>
<Button onPress={() => queue.add({title: 'Toasted!'})}>Toast</Button>
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>

```css
.react-aria-Toast {
  view-transition-class: toast;
}

::view-transition-new(.toast):only-child {
  animation: slide-in 400ms;
}

::view-transition-old(.toast):only-child {
  animation: slide-out 400ms;
}

@keyframes slide-out {
  to {
    translate: 100% 0;
    opacity: 0;
  }
}

@keyframes slide-in {
  from {
    translate: 100% 0;
    opacity: 0;
  }
}
```

</details>

## Props

### ToastRegion

`<ToastRegion>` renders a group of toasts.

<PropTable component={docs.exports.UNSTABLE_ToastRegion} links={docs.links} />

### Toast

`<Toast>` renders an individual toast.

<PropTable component={docs.exports.UNSTABLE_Toast} links={docs.links} />

### ToastContent

`<ToastContent>` renders the main content of a toast, including the title and description. It accepts all HTML attributes.

## ToastQueue API

A `ToastQueue` manages the state for a `<ToastRegion>`. The state is stored outside React so that you can trigger toasts from anywhere in your application, not just inside components.

<ClassAPI links={docs.links} class={docs.exports.UNSTABLE_ToastQueue} />
